#ifndef _COORDINATE_CLASS_H
#define _COORDINATE_CLASS_H

#include "fwdDeclarations.h"

#include <math.h>



// wishlist: return itself as cartesian, polar, spherical, etc..
// cartesian is universal.
// for the moment being, just have helpers to construct/return polar, spherical, etc..
class CoordinateClass {
public:
	// c is for cartesian, I guess
	union {struct {float c0,c1,c2;};float c[3];};
	float norm;
	// polar representation
	float r,th,ph;
	int validFlag;
	int userStatus;
	CoordinateClass() {
		c0=0.0f;c1=0.0f;c2=0.0f;
		r=0.0f;th=0.0f;ph=0.0f;
		norm=0.0f;
		validFlag=0;
		userStatus=0;
	};

	void UpdateNorm() {norm=sqrt(c0*c0+c1*c1+c2*c2);};
	
	CoordinateClass(float arg0,float arg1,float arg2) {
		c0=arg0;c1=arg1;c2=arg2;
		validFlag=1;
		UpdateNorm();
	};
	CoordinateClass(float arg[]) {
		c0=arg[0];c1=arg[1];c2=arg[2];
		validFlag=1;
		UpdateNorm();
	}
	void UpdateCartesianFromPolar() {
		c0=r*sin(ph)*cos(th);
		c1=r*sin(ph)*sin(th);
		c2=r*cos(ph);
		UpdateNorm();
	}

	void UpdatePolarFromCartesian() {
		r=norm;
		if(r!=0) {
			th=acos(c2/r);
			if(th!=0)
				ph=acos(c0/(r*sin(th)));
			// else: don't change ph
		}
		else validFlag=0;
	}

	CoordinateClass RValue_Polar(float r_arg,float th_arg,float ph_arg) {
		r=r_arg;th=th_arg;ph=ph_arg;
		validFlag=1;
		UpdateCartesianFromPolar();
		return *this;
	};

	CoordinateClass operator +(CoordinateClass arg) {
		CoordinateClass retVal = *this;
		retVal.c0+=arg.c0;
		retVal.c1+=arg.c1;
		retVal.c2+=arg.c2;
		retVal.UpdateNorm();
		return retVal;
	};

	CoordinateClass operator -(CoordinateClass arg) {
		CoordinateClass retVal = *this;
		retVal.c0-=arg.c0;
		retVal.c1-=arg.c1;
		retVal.c2-=arg.c2;
		retVal.UpdateNorm();
		return retVal;
	};

	// cross product, overloaded
	CoordinateClass operator *(CoordinateClass arg) {
		CoordinateClass retVal;
		retVal.c0= c1*arg.c2 - c2*arg.c1;
		retVal.c1=-c0*arg.c2 + c2*arg.c0;
		retVal.c2= c0*arg.c1 - c1*arg.c0;
		retVal.UpdateNorm();
		return retVal;
	};

	CoordinateClass operator *(float arg) {
		CoordinateClass retVal=*this;
		retVal.c0*=arg;retVal.c1*=arg;retVal.c2*=arg;
		retVal.norm*=arg;
		return retVal;
	};
	CoordinateClass operator /(float arg) {
		CoordinateClass retVal=*this;
		if(arg!=0.0f) {
			retVal.c0/=arg;retVal.c1/=arg;retVal.c2/=arg;
			retVal.norm/=arg;
		}
		else {
			retVal.validFlag=0;
		}
		return retVal;
	};
};

// philosophy: use both macros and software engineering. Client is happy, hackers are happy,
// I'm happy.

#endif 